home *** CD-ROM | disk | FTP | other *** search
/ Amiga Magazin: Amiga-CD 1997 September & October / Amiga-CD 1997 #9-10.iso / aminet / gameboyemulator / gb.c < prev    next >
C/C++ Source or Header  |  1995-10-29  |  15KB  |  498 lines

  1. /** VGB: portable GameBoy emulator ***************************/
  2. /**                                                         **/
  3. /**                           GB.c                          **/
  4. /**                                                         **/
  5. /** This file contains the portable part of the GameBoy     **/
  6. /** hardware emulation. See GB.h for #defines related to    **/
  7. /** drivers and GameBoy hardware.                           **/
  8. /**                                                         **/
  9. /** Copyright (C) Marat Fayzullin 1995                      **/
  10. /**     You are not allowed to distribute this software     **/
  11. /**     commercially. Please, notify me, if you make any    **/   
  12. /**     changes to this file.                               **/
  13. /*************************************************************/
  14.  
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <string.h>
  18. #include <ctype.h>
  19.  
  20. #include "GB.h" 
  21.  
  22. byte Verbose    = 1;     /* Verboseness level                            */
  23.  
  24. byte *RAM=NULL;          /* Pointer to Z80 address space (64kB)          */
  25.  
  26. int  VPeriod    = 6000;  /* Number of Z80 cycles between VBlanks         */
  27. int  UPeriod    = 1;     /* Number of VBlanks per screen update          */
  28. int  TPeriod;            /* Number of Z80 cycles per screen scanline     */
  29. byte LineDelay  = 1;     /* When 1, CMPLINE interrupts are delayed       */
  30.  
  31. char *SaveName  = NULL;  /* .sav file name                               */
  32.  
  33. struct                   /* Cheat list to be filled before StartGB()     */
  34. {                        /* is called                                    */
  35.   byte Value,Bank;
  36.   word Address;
  37. } Cheats[MAXCHEAT];
  38. int CheatCount  = 0;     /* Number of cheats in the list                 */
  39.  
  40. FILE *SerialOut;         /* Output stream emulating the serial line      */
  41. FILE *SerialIn;          /* Input stream emulating the serial line       */
  42. byte SerialBuf;          /* Next byte to output via the serial line      */
  43.  
  44. byte MBCType;            /* MBC type: 1 for MBC2, 0 for MBC1             */
  45. byte *ROMMap[256];       /* Addresses of ROM banks                       */
  46. byte ROMBank;            /* Number of ROM bank currently used            */
  47. byte ROMMask;            /* Mask for the ROM bank number                 */
  48. int  ROMBanks;           /* Total number of ROM banks                    */
  49. byte *RAMMap[256];       /* Addresses of RAM banks                       */ 
  50. byte RAMBank;            /* Number of RAM bank currently used            */
  51. byte RAMMask;            /* Mask for the RAM bank number                 */
  52. int  RAMBanks;           /* Total number of RAM banks                    */
  53.  
  54. byte JoyState   = 0xFF;  /* Joystick state: START.SELECT.B.A.D.U.L.R     */
  55.  
  56. byte BPal[4];            /* Background palette                           */
  57. byte SPal0[4],SPal1[4];  /* Sprite palettes                              */
  58.  
  59. byte *ChrGen;            /* Character generator                          */
  60. byte *BgdTab,*WndTab;    /* Background and window character tables       */
  61.  
  62. byte SprFlag    = 0;     /* <>0: sprites were enabled during the frame   */
  63.  
  64. void DoWrite(word A,byte V);
  65.  
  66.  
  67.  
  68. void M_WRMEM(word A,byte V)
  69. {
  70.   switch(A&0xE000)
  71.   {
  72.     case 0x0000:
  73.     case 0x6000:
  74.       if(Verbose&0x02) printf("Wrote %Xh to ROM at %Xh\n",V,A);
  75.       return;
  76.     case 0x2000:
  77.       if(MBCType&&((A&0xFF00)!=0x2100)) return;
  78.       V&=ROMMask;
  79.       if(ROMBank!=V)
  80.       {
  81.         ROMBank=V;
  82.         if(ROMMap[V]) memcpy(RAM+0x4000,ROMMap[V],0x4000);
  83.         else          memset(RAM+0x4000,NORAM,0x4000);
  84.         if(Verbose&0x08) printf("ROM: Bank %d selected\n",V);
  85.       }
  86.       return;
  87.     case 0x4000:
  88.       V&=RAMMask;
  89.       if(!MBCType&&(RAMBank!=V))
  90.       {
  91.         if(RAMMap[RAMBank]) memcpy(RAMMap[RAMBank],RAM+0xA000,0x2000);
  92.         RAMBank=V;
  93.         if(RAMMap[V]) memcpy(RAM+0xA000,RAMMap[V],0x2000);
  94.         else          memset(RAM+0xA000,NORAM,0x2000);
  95.         if(Verbose&0x08) printf("RAM: Bank %d selected\n",V);
  96.       }
  97.       return;
  98.     case 0x8000:
  99.     case 0xA000:
  100.     case 0xC000:
  101.       RAM[A]=V;return;
  102.     case 0xE000:
  103.       DoWrite(A,V);return;
  104.   }
  105. }
  106.  
  107. void DoWrite(word A,byte V)
  108. {
  109.   static byte TPShifts[] = { 6,0,2,4 };
  110.  
  111.   switch(A)
  112.   {
  113.     case 0xFF00: JOYPAD=0xCF|V;
  114.                  if(!(V&0x20)) JOYPAD&=(JoyState>>4)|0xF0;
  115.                  if(!(V&0x10)) JOYPAD&=JoyState|0xF0; 
  116.                  return;
  117.     case 0xFF01: SerialBuf=V;return;
  118.     case 0xFF02: if(V&0x80)
  119.                  { 
  120.                    IFLAGS|=0x08;
  121.                    if(SerialOut) fputc(SerialBuf,SerialOut);
  122.                  }
  123.                  V|=0x7E;break;
  124.     case 0xFF05: V=0;break;
  125.     case 0xFF07: TPeriod=1<<TPShifts[V&0x03];
  126.                  V|=0xF8;break;
  127.     case 0xFF0F: V|=0xE0;break;
  128.     case 0xFFFF: V|=0xE0;break;
  129.     case 0xFF46: memcpy(RAM+0xFE00,RAM+((word)V<<8),0xA0);
  130.                  return;
  131.     case 0xFF41: V=(V&0xF8)|(LCDSTAT&0x07);
  132.                  break;
  133.     case 0xFF40: ChrGen=RAM+(V&0x10? 0x8000:0x8800);
  134.                  BgdTab=RAM+(V&0x08? 0x9C00:0x9800);
  135.                  WndTab=RAM+(V&0x40? 0x9C00:0x9800);
  136.                  break;
  137.     case 0xFF44: V=0;break;
  138.     case 0xFF47: BPal[0]=V&0x03;
  139.                  BPal[1]=(V&0x0C)>>2;
  140.                  BPal[2]=(V&0x30)>>4;
  141.                  BPal[3]=(V&0xC0)>>6;
  142.                  break;
  143.     case 0xFF48: SPal0[0]=V&0x03;
  144.                  SPal0[1]=(V&0x0C)>>2;
  145.                  SPal0[2]=(V&0x30)>>4;
  146.                  SPal0[3]=(V&0xC0)>>6;
  147.                  break;
  148.     case 0xFF49: SPal1[0]=V&0x03;
  149.                  SPal1[1]=(V&0x0C)>>2;
  150.                  SPal1[2]=(V&0x30)>>4;
  151.                  SPal1[3]=(V&0xC0)>>6;
  152.                  break;
  153.   }
  154.   RAM[A]=V;
  155. }
  156.  
  157. int StartGB(char *CartName)
  158. {
  159.   static char *CartTypes[] =
  160.   {
  161.     "ROM ONLY","ROM+MBC1","ROM+MBC1+RAM",
  162.     "ROM+MBC1+RAM+BATTERY","UNKNOWN",
  163.     "ROM+MBC2","ROM+MBC2+BATTERY"
  164.   };
  165.  
  166.   static struct { word Code;char *Name; } Companies[] =
  167.   {
  168.     { 0x3301,"Nintendo"  },{ 0x7901,"Accolade"  },{ 0xA400,"Konami"    },
  169.     { 0x6701,"Ocean"     },{ 0x5601,"LJN"       },{ 0x9900,"ARC?"      },
  170.     { 0x0101,"Nintendo"  },{ 0x0801,"Capcom"    },{ 0x0100,"Nintendo"  },
  171.     { 0xBB01,"SunSoft"   },{ 0xA401,"Konami"    },{ 0xAF01,"Namcot?"   },
  172.     { 0xCA01,"Palcom?"   },{ 0xB601,"HAL?"      },{ 0x9C01,"Imagineer" },
  173.     { 0xB101,"NexSoft?"  },{ 0x5101,"Acclaim?"  },{ 0x6001,"Titus?"    },
  174.     { 0xB601,"HAL?"      },{ 0xCA01,"Palcom?"   },{ 0x3300,"Nintendo?" },
  175.     { 0x5401,"Gametek?"  },{ 0x7F01,"Kemco?"    },{ 0x4901,"Irem?"     },
  176.     { 0x7001,"Infogrames?"    },{ 0x8B01,"Bullet-Proof Software?" },
  177.     { 0x6101,"Virgin Games"   },{ 0x5501,"Park Place?" },
  178.     { 0x5D01,"Tradewest?"     },{ 0x6F01,"ElectroBrain?" },
  179.     { 0xAA01,"Broderbund?"    },{ 0xC301,"SquareSoft?" },
  180.     { 0x5201,"Activision?"    },{ 0x5A01,"Bitmap Brothers/Mindscape" },
  181.     { 0x5301,"American Sammy" },{ 0x1801,"Hudson Soft"},{ 0x0000,NULL }
  182.   };
  183.  
  184.   int Checksum,I,J,*T;
  185.   FILE *F;
  186.   char *P;
  187.   word A;
  188.   reg R;
  189.  
  190.   /*** STARTUP CODE starts here: ***/
  191.   T=(int *)"\01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
  192. #ifdef LSB_FIRST
  193.   if(*T!=1)
  194.   {
  195.     puts("********** This machine is high-endian. *********");
  196.     puts("Take #define LSB_FIRST out and compile VGB again.");
  197.     return(0);
  198.   }
  199. #else
  200.   if(*T==1)
  201.   {
  202.     puts("********* This machine is low-endian. *********");
  203.     puts("Insert #define LSB_FIRST and compile VGB again.");
  204.     return(0);
  205.   }
  206. #endif
  207.  
  208.   for(I=0;I<256;I++) RAMMap[I]=ROMMap[I]=NULL;
  209.  
  210.   SerialIn=stdin;SerialOut=NULL;
  211.  
  212.   if(Verbose) printf("Allocating 64kB for address space...");
  213.   if(!(RAM=malloc(0x10000)))
  214.   { if(Verbose) puts("FAILED");return(0); }
  215.   memset(RAM,0,0x10000);
  216.  
  217.   if(Verbose) printf("OK\nOpening %s...",CartName);
  218.   if(!(F=fopen(CartName,"rb")))
  219.   { if(Verbose) puts("FAILED");return(0); }
  220.  
  221.   if(Verbose) printf("reading...");
  222.   if(fread(RAM,1,0x4000,F)!=0x4000)
  223.   { if(Verbose) puts("FAILED");return(0); }
  224.  
  225.   ROMMap[0]=RAM;
  226.   ROMBanks=2<<RAM[0x0148];
  227.   RAMBanks=(1<<RAM[0x0149]*2)>>1;
  228.   Checksum=((word)RAM[0x014E]<<8)+RAM[0x014F];
  229.   MBCType=RAM[0x0147]>3;
  230.  
  231.   P=NULL;
  232.   if((RAM[0x0147]==4)||(RAM[0x0147]>6)) P="Unknown ROM type";
  233.   if(RAM[0x0100]||(RAM[0x0101]!=0xC3))  P="Invalid cartridge ROM";
  234.   if(P)
  235.   {
  236.     printf("\nError loading cartridge: %s\n",P);
  237.     fclose(F);return(0);
  238.   }
  239.  
  240.   if(Verbose)
  241.   {
  242.     printf("OK\n  Name: %s\n",RAM+0x0134);
  243.     printf("  Type: %s\n",CartTypes[RAM[0x0147]]);
  244.     printf("  ROM Size: %dx16kB\n",ROMBanks);
  245.     printf("  RAM Size: %dx8kB\n",RAMBanks);
  246.  
  247.     J=((word)RAM[0x014B]<<8)+RAM[0x014A];
  248.     for(I=0,P=NULL;!P&&Companies[I].Name;I++)
  249.       if(J==Companies[I].Code) P=Companies[I].Name;
  250.     printf("  Manufacturer ID: %Xh",J);
  251.     printf(" [%s]\n",P? P:"?");
  252.  
  253.     printf("  Version Number: %Xh\n",RAM[0x014C]);
  254.     printf("  Complement Check: %Xh\n",RAM[0x014D]);
  255.     printf("  Checksum: %Xh\n",Checksum);
  256.     J=((word)RAM[0x0103]<<8)+RAM[0x0102];
  257.     printf("  Start Address: %Xh\n",J);
  258.   }
  259.  
  260.   Checksum+=RAM[0x014E]+RAM[0x014F];
  261.   for(I=0;I<0x4000;I++) Checksum-=RAM[I];
  262.  
  263.   if(Verbose) printf("Loading %dx16kB ROM banks:\n.",ROMBanks);
  264.   for(I=1;I<ROMBanks;I++)
  265.     if(ROMMap[I]=malloc(0x4000))
  266.       if(fread(ROMMap[I],1,0x4000,F)==0x4000)
  267.       {
  268.         for(J=0;J<0x4000;J++) Checksum-=ROMMap[I][J];
  269.         if(Verbose) putchar('.');
  270.       }
  271.       else { if(Verbose) puts("READ FAILED");break; }
  272.     else { if(Verbose) puts("MALLOC FAILED");break; }
  273.  
  274.   fclose(F);if(I<ROMBanks) return(0);
  275.  
  276.   if(Checksum&0xFFFF)
  277.     {
  278.         printf("\nError loading cartridge: Checksum is wrong\n\
  279. (Should be $0000 - is $%lx !)\nStart anyway (y/n)?",(Checksum&0xffff));
  280.     if(getchar() != 'y')    return(0);
  281.     }
  282.  
  283.   if(RAMBanks&&Verbose)
  284.     printf("OK\nAllocating %dx8kB RAM banks...",RAMBanks);
  285.   for(I=0;I<RAMBanks;I++)
  286.     if(RAMMap[I]=malloc(0x2000))
  287.       memset(RAMMap[I],0,0x2000);
  288.     else
  289.     { if(Verbose) puts("FAILED");return(0); }
  290.  
  291.   puts("OK");
  292.  
  293.   if(((RAM[0x0147]==3)||(RAM[0x0147]==6))&&RAMMap[0])
  294.     if(SaveName=malloc(strlen(CartName)+10))
  295.     {
  296.       strcpy(SaveName,CartName);
  297.       if(P=strrchr(SaveName,'.')) strcpy(P,".sav");
  298.       else strcat(SaveName,".sav");
  299.       if(Verbose) printf("Opening %s...",SaveName);
  300.       if(F=fopen(SaveName,"rb"))
  301.       {
  302.         if(Verbose) printf("reading...");
  303.         J=(fread(RAMMap[0],1,0x2000,F)==0x2000);
  304.         if(Verbose) puts(J? "OK":"FAILED");
  305.         fclose(F);
  306.       }
  307.       else if(Verbose) puts("FAILED");
  308.     }
  309.  
  310.   if(CheatCount>0)
  311.   {
  312.     if(Verbose) puts("Patching cheats into the ROM code:");
  313.     for(J=0;J<CheatCount;J++)
  314.     {
  315.       I=Cheats[J].Bank;A=Cheats[J].Address;
  316.       printf("  %d:%Xh = %Xh - ",I,A,Cheats[J].Value);
  317.       if(I<ROMBanks)
  318.         if(ROMMap[I])
  319.         { *(ROMMap[I]+A)=Cheats[J].Value;P="OK"; }
  320.         else P="FAILED. No ROM in this bank.";
  321.       else P="FAILED. Invalid bank number.";
  322.       puts(P);
  323.     }
  324.   }
  325.  
  326.   for(ROMMask=0x01,I=ROMBanks;I;ROMMask<<=1,I>>=1);ROMMask--;ROMBank=1;
  327.   for(RAMMask=0x01,I=RAMBanks;I;RAMMask<<=1,I>>=1);RAMMask--;RAMBank=0;
  328.     
  329.   if(RAMMap[0]) memcpy(RAM+0xA000,RAMMap[0],0x2000);
  330.   if(ROMMap[1]) memcpy(RAM+0x4000,ROMMap[1],0x4000);
  331.  
  332.   IPeriod=VPeriod/154;TPeriod=64;
  333.  
  334.   ChrGen=RAM+0x8800;BgdTab=WndTab=RAM+0x9800;
  335.   LCDCONT=0x81;LCDSTAT=0x00;
  336.   CURLINE=0x00;CMPLINE=0xFF;
  337.   IFLAGS=ISWITCH=0xE0;
  338.   TIMECNT=TIMEMOD=0x00;
  339.   TIMEFRQ=0xF8;
  340.   SIOCONT=0x00;
  341.  
  342.   for(I=0;I<4;I++) SPal0[I]=SPal1[I]=BPal[I]=I;
  343.   BGRDPAL=SPR0PAL=SPR1PAL=0xE4;
  344.  
  345.   R.PC.W=0x0100;R.SP.W=0xF000;R.IFF=0;
  346.   if(Verbose) printf("RUNNING ROM CODE...\n");
  347.   A=Z80(RAM,R);
  348.  
  349.   if(Verbose) printf("EXITED at PC = %Xh.\n",A); 
  350.   return(1);
  351. }
  352.  
  353. void TrashGB(void)
  354. {
  355.   FILE *F;
  356.   int I;
  357.  
  358.   if(SaveName&&RAMMap[0])   
  359.   {
  360.     if(Verbose) printf("\nOpening %s...",SaveName);   
  361.     if(F=fopen(SaveName,"wb"))
  362.     { 
  363.       if(Verbose) printf("writing...");
  364.       I=(fwrite(RAMBank? RAMMap[0]:(RAM+0xA000),1,0x2000,F)==0x2000);
  365.       if(Verbose) puts(I? "OK":"FAILED");
  366.       fclose(F);
  367.     }
  368.     else if(Verbose) puts("FAILED");
  369.   }
  370.  
  371.   if(SaveName) free(SaveName);
  372.   if(RAM) free(RAM);
  373.   for(I=1;ROMMap[I];I++) free(ROMMap[I]);
  374.   for(I=0;RAMMap[I];I++) free(RAMMap[I]);
  375. }
  376.  
  377. word Interrupt(void)
  378. {
  379.   static int TCount=1;
  380.   static int UCount=1;
  381.   register word A;
  382.   register byte J;
  383.  
  384.   A=0xFFFF;DIVREG++;
  385.   SprFlag|=LCDCONT&0x02;
  386.   J=(0x08<<(LCDSTAT&0x03))&0x3F;
  387.  
  388.   if(LineDelay)
  389.   {
  390.     if(!UCount&&(CURLINE<144)) RefreshLine(CURLINE);
  391.     CURLINE=(CURLINE>=153)? 0:CURLINE+1;
  392.     if(CURLINE==CMPLINE) { LCDSTAT|=0x04;J|=0x40; }
  393.   }
  394.   else
  395.   {
  396.     if(CURLINE==CMPLINE) { LCDSTAT|=0x04;J|=0x40; }
  397.     CURLINE=(CURLINE>=153)? 0:CURLINE+1;
  398.     if(!UCount&&(CURLINE<144)) RefreshLine(CURLINE);
  399.   }
  400.  
  401.   /* If end of frame reached... */
  402.   if(CURLINE==145)
  403.   {
  404.     if(!UCount)
  405.     {
  406.       if((LCDCONT&0x80)&&SprFlag) RefreshSprites();
  407.       SprFlag=0;UCount=UPeriod;RefreshScreen();
  408.     }
  409.     else UCount--;
  410.  
  411.     /* Generating VBlank interrupt */
  412.     if((ISWITCH&VBL_IFLAG)&&(LCDCONT&0x80))
  413.     { IFLAGS|=VBL_IFLAG;A=0x0040; }
  414.   }
  415.  
  416.   /* Generating LCD controller interrupt */
  417.   if((J&LCDSTAT)&&(ISWITCH&LCD_IFLAG)&&(LCDCONT&0x80))
  418.   { IFLAGS|=LCD_IFLAG;A=0x0048; }
  419.  
  420.   /* Generating timer interrupt */
  421.   if(TIMEFRQ&0x04)
  422.     if(!--TCount)
  423.     {
  424.       TCount=TPeriod;
  425.       if(!++TIMECNT)
  426.       {
  427.         if(ISWITCH&TIM_IFLAG)
  428.         { IFLAGS|=TIM_IFLAG;A=0x0050; }
  429.         TIMECNT=TIMEMOD;
  430.       }
  431.     }
  432.  
  433.   /* Generating serial IO interrupt */
  434.   if(0/*SIOCONT&0x80*/)
  435.   {
  436.     SIOCONT&=0x7F;
  437.     if(ISWITCH&SIO_IFLAG)
  438.     { IFLAGS|=SIO_IFLAG;A=0x0058; }
  439.   }
  440.  
  441.   if(CURLINE==144)
  442.   {
  443.     IFLAGS=0x00;
  444.  
  445.     /* Updating joystick */
  446.     J=0xCF|JOYPAD;JoyState=Joystick();
  447.     if(!(J&0x10)) J&=JoyState|0xF0;
  448.     if(!(J&0x20)) J&=(JoyState>>4)|0xF0;
  449.  
  450.     /* Generating joystick interrupt */
  451.     if((J^JOYPAD)&JOYPAD)
  452.       if(ISWITCH&JOY_IFLAG)
  453.       { IFLAGS|=JOY_IFLAG;A=0x0060; }
  454.  
  455.     JOYPAD=J;
  456.   }
  457.  
  458.   return(A); 
  459.  
  460. int AddCheat(char *Cheat)
  461. {
  462.   static char Digits[]="0123456789ABCDEF";
  463.   int X1,X2;
  464.  
  465.   if(Verbose){ puts("Cheats are not supported yet!"); return(1);}
  466.  
  467.   if(CheatCount>=MAXCHEAT) return(0);
  468.   else
  469.   {
  470.     if((Cheat[3]!='-')||(Cheat[7]!='-')) return(0);
  471.     X1=strchr(Digits,toupper(Cheat[0]))-Digits;
  472.     X2=strchr(Digits,toupper(Cheat[1]))-Digits;
  473.     if((X1<0)||(X2<0)) return(0);
  474.     else Cheats[CheatCount].Value=X1*16+X2;
  475.     X1=strchr(Digits,toupper(Cheat[5]))-Digits;
  476.     X2=strchr(Digits,toupper(Cheat[4]))-Digits;
  477.     if((X1<0)||(X2<0)) return(0);
  478.     else Cheats[CheatCount].Address=X1*16+X2;
  479.     X1=strchr(Digits,toupper(Cheat[2]))-Digits;
  480.     X2=strchr(Digits,toupper(Cheat[6]))-Digits;
  481.     if((X1<0)||(X2<0)) return(0);
  482.     else Cheats[CheatCount].Address+=256*(X1*16+X2);
  483.     X1=strchr(Digits,toupper(Cheat[2]))-Digits;
  484.     if(X1<0) return(0); else Cheats[CheatCount].Bank=X1;
  485.  
  486.     if(Cheats[CheatCount].Address<0x4000)
  487.       Cheats[CheatCount].Bank=0; 
  488.     else
  489.       if(Cheats[CheatCount].Address<0x8000)
  490.         Cheats[CheatCount].Address-=0x4000;
  491.       else
  492.         return(0);
  493.  
  494.     CheatCount++;return(1);
  495.   }
  496. }
  497.